<template>
  <div class="fbx-viewer">
    <div ref="canvasContainer" class="canvas-container"></div>

    <!-- 图层控制面板 -->
    <div class="layer-panel" v-if="!isLoading && layerGroups.length > 0">
      <div class="panel-header">
        <h3>图层控制</h3>
        <button @click="toggleLayerPanel" class="toggle-btn">
          <i
            :class="
              layerPanelVisible ? 'fas fa-chevron-up' : 'fas fa-chevron-down'
            "
          ></i>
        </button>
      </div>
      <div class="layer-list" v-show="layerPanelVisible">
        <div
          v-for="layer in layerGroups"
          :key="layer.id"
          class="layer-item"
          :class="{ selected: selectedLayerId === layer.id }"
        >
          <div class="layer-controls">
            <input
              type="checkbox"
              :checked="layer.visible"
              @change="toggleLayerVisibility(layer.id)"
              class="visibility-toggle"
            />
            <span class="layer-name" @click="selectLayer(layer.id)">
              {{ layer.name }}
            </span>
            <div class="layer-actions">
              <button
                @click="highlightLayer(layer.id)"
                class="action-btn"
                title="高亮图层"
              >
                <i class="fas fa-highlighter"></i>
              </button>
              <button
                @click="isolateLayer(layer.id)"
                class="action-btn"
                title="单独显示"
              >
                <i class="fas fa-eye"></i>
              </button>
            </div>
          </div>
        </div>
      </div>
    </div>

    <!-- 控制栏 -->
    <div class="controls-bar">
      <button @click="resetView" class="control-btn" title="重置视角">
        <i class="fas fa-compress-arrows-alt"></i>
      </button>
      <button @click="clearSelection" class="control-btn" title="清除选择">
        <i class="fas fa-eraser"></i>
      </button>
      <button @click="showAllLayers" class="control-btn" title="显示所有图层">
        <i class="fas fa-layer-group"></i>
      </button>
      <button
        @click="clearLayerSelection"
        class="control-btn"
        title="清除图层选择"
        v-if="selectedLayerId"
      >
        <i class="fas fa-times"></i>
      </button>
      <div class="info" v-if="selectedFaceInfo">
        选中面 ID: {{ selectedFaceInfo.id }}
        <span v-if="selectedFaceInfo.layerName">
          | 图层: {{ selectedFaceInfo.layerName }}</span
        >
      </div>
      <div class="info" v-if="selectedLayerInfo">
        选中图层: {{ selectedLayerInfo.name }}
      </div>
    </div>

    <!-- 加载状态 -->
    <div v-if="isLoading" class="loading">加载中...</div>

    <!-- 操作提示 -->
    <div v-if="!isLoading && layerGroups.length > 0" class="help-tip">
      <i class="fas fa-mouse-pointer"></i>
      <span>点击模型上的任意部分选择图层</span>
    </div>
  </div>
</template>

<script setup>
import { ref, onMounted, onBeforeUnmount } from "vue";
import * as THREE from "three";
import { FBXLoader } from "three/addons/loaders/FBXLoader.js";
import { OrbitControls } from "three/addons/controls/OrbitControls.js";

// 响应式状态
const canvasContainer = ref(null);
const isLoading = ref(true);
const selectedFaceInfo = ref(null);

// 图层相关状态
const layerGroups = ref([]);
const selectedLayerId = ref(null);
const selectedLayerInfo = ref(null);
const layerPanelVisible = ref(true);

// Three.js核心对象
let scene, camera, renderer, controls, raycaster, mouse;
let model,
  originalMaterials = new Map(); // 存储原始材质，用于恢复
let layerMaterials = new Map(); // 存储图层材质
let animationId = null;

// 初始化场景
const initThreeScene = () => {
  // 创建场景
  scene = new THREE.Scene();
  scene.background = new THREE.Color(0xf0f0f0);

  // 添加辅助网格
  const gridHelper = new THREE.GridHelper(10, 10);
  scene.add(gridHelper);

  // 创建相机
  camera = new THREE.PerspectiveCamera(
    75,
    canvasContainer.value.clientWidth / canvasContainer.value.clientHeight,
    0.1,
    1000
  );
  camera.position.set(5, 5, 5);

  // 创建渲染器
  renderer = new THREE.WebGLRenderer({ antialias: true });
  renderer.setSize(
    canvasContainer.value.clientWidth,
    canvasContainer.value.clientHeight
  );
  canvasContainer.value.appendChild(renderer.domElement);

  // 初始化控制器
  controls = new OrbitControls(camera, renderer.domElement);
  controls.enableDamping = true;

  // 添加光源
  const ambientLight = new THREE.AmbientLight(0xffffff, 0.5);
  scene.add(ambientLight);

  const directionalLight = new THREE.DirectionalLight(0xffffff, 0.8);
  directionalLight.position.set(5, 10, 7.5);
  scene.add(directionalLight);

  // 初始化射线投射器（用于检测点击）
  raycaster = new THREE.Raycaster();
  mouse = new THREE.Vector2();

  // 添加鼠标点击事件监听
  canvasContainer.value.addEventListener("click", onCanvasClick);
  // 添加窗口大小调整监听
  window.addEventListener("resize", onWindowResize);
};

// 加载FBX模型
const loadFbxModel = () => {
  const loader = new FBXLoader();

  loader.load(
    "/models/example.fbx", // 模型路径
    (object) => {
      model = object;
      scene.add(model);

      // 分析模型结构，识别图层块
      analyzeModelLayers();

      // 模型处理：确保可以检测到单个面
      model.traverse((child) => {
        if (child.isMesh) {
          // 启用几何体的索引，确保射线能检测到具体面
          child.geometry.computeVertexNormals();
          child.geometry.computeBoundingBox();

          // 存储原始材质，用于后续恢复
          originalMaterials.set(child, child.material);
        }
      });

      // 调整模型位置和大小
      model.scale.set(0.01, 0.01, 0.01);
      resetView();

      isLoading.value = false;
    },
    (xhr) => {
      console.log(`加载进度: ${Math.round((xhr.loaded / xhr.total) * 100)}%`);
    },
    (error) => {
      console.error("模型加载失败:", error);
      isLoading.value = false;
    }
  );
};

// 分析模型图层结构
const analyzeModelLayers = () => {
  const layers = new Map();

  model.traverse((child) => {
    if (child.isMesh) {
      // 优先使用网格对象本身的名称，然后是父级名称
      let layerName = child.name;

      // 如果网格没有名称，尝试使用父级名称
      if (!layerName && child.parent) {
        layerName = child.parent.name;
      }

      // 如果还是没有名称，使用默认名称
      if (!layerName) {
        layerName = "未命名图层";
      }

      if (!layers.has(layerName)) {
        layers.set(layerName, {
          id: layerName,
          name: layerName,
          objects: [],
          visible: true,
          originalMaterials: new Map(),
        });
      }

      const layer = layers.get(layerName);
      layer.objects.push(child);

      // 存储原始材质
      if (child.material) {
        layer.originalMaterials.set(child, child.material);
      }
    }
  });

  // 如果没有找到任何图层，创建一个默认图层包含所有网格
  if (layers.size === 0) {
    const defaultLayer = {
      id: "默认图层",
      name: "默认图层",
      objects: [],
      visible: true,
      originalMaterials: new Map(),
    };

    model.traverse((child) => {
      if (child.isMesh) {
        defaultLayer.objects.push(child);
        if (child.material) {
          defaultLayer.originalMaterials.set(child, child.material);
        }
      }
    });

    if (defaultLayer.objects.length > 0) {
      layers.set("默认图层", defaultLayer);
    }
  }

  // 转换为响应式数组
  layerGroups.value = Array.from(layers.values());
  console.log("识别到的图层:", layerGroups.value);
};

// 根据网格对象查找所属图层
const findLayerByMesh = (mesh) => {
  for (const layer of layerGroups.value) {
    if (layer.objects.includes(mesh)) {
      return layer;
    }
  }
  return null;
};

// 处理鼠标点击事件
const onCanvasClick = (event) => {
  if (!model) return;

  // 计算鼠标在标准化设备坐标中的位置 (-1 到 1)
  const rect = canvasContainer.value.getBoundingClientRect();
  mouse.x = ((event.clientX - rect.left) / rect.width) * 2 - 1;
  mouse.y = -((event.clientY - rect.top) / rect.height) * 2 + 1;

  // 更新射线投射器
  raycaster.setFromCamera(mouse, camera);

  // 检测与模型的交集
  const intersects = raycaster.intersectObject(model, true);

  if (intersects.length > 0) {
    // 获取第一个交点（最近的面）
    const intersection = intersects[0];
    const mesh = intersection.object;
    const faceIndex = intersection.faceIndex;

    // 找到点击的网格所属的图层
    const clickedLayer = findLayerByMesh(mesh);

    if (clickedLayer) {
      // 选择并高亮该图层
      selectLayer(clickedLayer.id);

      // 记录选中的面信息
      selectedFaceInfo.value = {
        id: faceIndex,
        position: intersection.point.toArray().map((v) => v.toFixed(2)),
        layerName: clickedLayer.name,
      };
    } else {
      // 如果没有找到图层，清除选择
      clearLayerSelection();
      clearSelection();

      // 记录选中的面信息
      selectedFaceInfo.value = {
        id: faceIndex,
        position: intersection.point.toArray().map((v) => v.toFixed(2)),
      };
    }
  }
};

// 高亮选中的面
const highlightSelectedFace = (mesh, faceIndex) => {
  // 创建高亮材质
  const highlightMaterial = new THREE.MeshBasicMaterial({
    color: 0xff0000, // 红色高亮
    side: THREE.DoubleSide,
    transparent: true,
    opacity: 0.7,
  });

  // 如果是单个面，创建一个仅包含该面的新网格
  if (mesh.geometry.index) {
    // 提取选中的面
    const originalGeometry = mesh.geometry;
    const newGeometry = new THREE.BufferGeometry();

    // 获取面的顶点索引
    const index = originalGeometry.index.array;
    const vertices = originalGeometry.attributes.position.array;

    // 提取当前面的三个顶点
    const faceVertices = [];
    for (let i = 0; i < 3; i++) {
      const vertexIndex = index[faceIndex * 3 + i] * 3;
      faceVertices.push(
        vertices[vertexIndex],
        vertices[vertexIndex + 1],
        vertices[vertexIndex + 2]
      );
    }

    // 创建新几何体
    newGeometry.setAttribute(
      "position",
      new THREE.Float32BufferAttribute(faceVertices, 3)
    );
    newGeometry.computeVertexNormals();

    // 创建高亮网格并添加到场景
    const highlightMesh = new THREE.Mesh(newGeometry, highlightMaterial);
    highlightMesh.position.copy(mesh.position);
    highlightMesh.rotation.copy(mesh.rotation);
    highlightMesh.scale.copy(mesh.scale);
    highlightMesh.matrix.copy(mesh.matrix);
    highlightMesh.matrixAutoUpdate = false;

    // 将高亮网格作为子对象添加，确保位置同步
    mesh.add(highlightMesh);

    // 存储高亮网格引用，用于后续清除
    mesh.userData.highlightMesh = highlightMesh;
  }
};

// 清除选择状态
const clearSelection = () => {
  if (!model) return;

  // 移除所有高亮网格
  model.traverse((child) => {
    if (child.isMesh && child.userData.highlightMesh) {
      child.remove(child.userData.highlightMesh);
      child.userData.highlightMesh.geometry.dispose();
      child.userData.highlightMesh.material.dispose();
      child.userData.highlightMesh = null;
    }
  });

  selectedFaceInfo.value = null;
};

// 图层操作函数
const toggleLayerPanel = () => {
  layerPanelVisible.value = !layerPanelVisible.value;
};

const toggleLayerVisibility = (layerId) => {
  const layer = layerGroups.value.find((l) => l.id === layerId);
  if (layer) {
    layer.visible = !layer.visible;

    // 控制图层对象的可见性
    layer.objects.forEach((obj) => {
      obj.visible = layer.visible;
    });
  }
};

const selectLayer = (layerId) => {
  // 清除之前的高亮
  clearLayerHighlights();

  selectedLayerId.value = layerId;
  const layer = layerGroups.value.find((l) => l.id === layerId);
  selectedLayerInfo.value = layer ? { name: layer.name, id: layer.id } : null;

  // 为选中的图层应用选中颜色
  if (layer) {
    highlightSelectedLayer(layer);
  }
};

// 高亮选中的图层（点击选择时使用）
const highlightSelectedLayer = (layer) => {
  // 为选中图层创建蓝色高亮材质
  const selectedMaterial = new THREE.MeshBasicMaterial({
    color: 0x4a90e2, // 蓝色高亮
    side: THREE.DoubleSide,
    transparent: true,
    opacity: 0.7,
  });

  // 应用选中材质到图层中的所有网格
  layer.objects.forEach((obj) => {
    if (obj.isMesh) {
      // 存储原始材质
      if (!layerMaterials.has(obj)) {
        layerMaterials.set(obj, obj.material);
      }
      obj.material = selectedMaterial;
    }
  });
};

const highlightLayer = (layerId) => {
  const layer = layerGroups.value.find((l) => l.id === layerId);
  if (!layer) return;

  // 清除之前的高亮
  clearLayerHighlights();

  // 为图层创建绿色高亮材质
  const highlightMaterial = new THREE.MeshBasicMaterial({
    color: 0x00ff00, // 绿色高亮
    side: THREE.DoubleSide,
    transparent: true,
    opacity: 0.8,
  });

  // 应用高亮材质到图层中的所有网格
  layer.objects.forEach((obj) => {
    if (obj.isMesh) {
      // 存储原始材质
      if (!layerMaterials.has(obj)) {
        layerMaterials.set(obj, obj.material);
      }
      obj.material = highlightMaterial;
    }
  });
};

const clearLayerHighlights = () => {
  // 恢复所有图层的原始材质
  layerGroups.value.forEach((layer) => {
    layer.objects.forEach((obj) => {
      if (obj.isMesh && layerMaterials.has(obj)) {
        obj.material = layerMaterials.get(obj);
      }
    });
  });
  layerMaterials.clear();
};

const isolateLayer = (layerId) => {
  const targetLayer = layerGroups.value.find((l) => l.id === layerId);
  if (!targetLayer) return;

  // 先选择该图层
  selectLayer(layerId);

  // 隐藏所有其他图层
  layerGroups.value.forEach((layer) => {
    if (layer.id !== layerId) {
      layer.visible = false;
      layer.objects.forEach((obj) => {
        obj.visible = false;
      });
    } else {
      layer.visible = true;
      layer.objects.forEach((obj) => {
        obj.visible = true;
      });
    }
  });
};

const showAllLayers = () => {
  // 显示所有图层
  layerGroups.value.forEach((layer) => {
    layer.visible = true;
    layer.objects.forEach((obj) => {
      obj.visible = true;
    });
  });

  // 如果有选中的图层，重新应用选中高亮
  if (selectedLayerId.value) {
    const selectedLayer = layerGroups.value.find(
      (l) => l.id === selectedLayerId.value
    );
    if (selectedLayer) {
      clearLayerHighlights();
      highlightSelectedLayer(selectedLayer);
    }
  } else {
    // 清除高亮
    clearLayerHighlights();
  }
};

// 清除图层选择
const clearLayerSelection = () => {
  selectedLayerId.value = null;
  selectedLayerInfo.value = null;
  clearLayerHighlights();
};

// 重置视角
const resetView = () => {
  if (!model) return;

  const box = new THREE.Box3().setFromObject(model);
  const center = box.getCenter(new THREE.Vector3());
  const size = box.getSize(new THREE.Vector3());
  const maxDim = Math.max(size.x, size.y, size.z);
  const fov = camera.fov * (Math.PI / 180);
  const cameraZ = Math.abs(maxDim / 2 / Math.tan(fov / 2)) * 1.5;

  camera.position.set(cameraZ, cameraZ, cameraZ);
  camera.lookAt(center);
  controls.target.copy(center);
};

// 窗口大小调整
const onWindowResize = () => {
  if (!camera || !renderer || !canvasContainer.value) return;

  const width = canvasContainer.value.clientWidth;
  const height = canvasContainer.value.clientHeight;

  camera.aspect = width / height;
  camera.updateProjectionMatrix();
  renderer.setSize(width, height);
};

// 动画循环
const animate = () => {
  animationId = requestAnimationFrame(animate);
  controls.update();
  renderer.render(scene, camera);
};

// 生命周期
onMounted(() => {
  if (canvasContainer.value) {
    initThreeScene();
    loadFbxModel();
    animate();
  }
});

onBeforeUnmount(() => {
  // 清理资源
  window.removeEventListener("resize", onWindowResize);
  canvasContainer.value?.removeEventListener("click", onCanvasClick);

  if (animationId) cancelAnimationFrame(animationId);
  if (renderer) renderer.dispose();
  if (controls) controls.dispose();

  // 清理场景
  if (scene) {
    scene.clear();
  }

  // 释放材质资源
  originalMaterials.forEach((material) => {
    material.dispose();
  });
  originalMaterials.clear();
});
</script>

<style scoped>
.fbx-viewer {
  width: 100%;
  height: 100vh;
  position: relative;
}

.canvas-container {
  width: 100%;
  height: 100%;
}

.controls-bar {
  position: absolute;
  bottom: 20px;
  left: 50%;
  transform: translateX(-50%);
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 16px;
  background: rgba(255, 255, 255, 0.9);
  border-radius: 20px;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
  z-index: 10;
}

.control-btn {
  width: 36px;
  height: 36px;
  border-radius: 50%;
  border: none;
  background: #fff;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: all 0.2s;
}

.control-btn:hover {
  background: #f0f0f0;
}

.info {
  color: #333;
  font-size: 14px;
  padding: 0 10px;
}

.loading {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  color: #666;
  font-size: 18px;
}

.help-tip {
  position: absolute;
  top: 20px;
  left: 50%;
  transform: translateX(-50%);
  background: rgba(74, 144, 226, 0.9);
  color: white;
  padding: 8px 16px;
  border-radius: 20px;
  font-size: 14px;
  display: flex;
  align-items: center;
  gap: 8px;
  z-index: 15;
  animation: fadeInOut 3s ease-in-out;
}

.help-tip i {
  font-size: 12px;
}

@keyframes fadeInOut {
  0% {
    opacity: 0;
    transform: translateX(-50%) translateY(-10px);
  }
  20% {
    opacity: 1;
    transform: translateX(-50%) translateY(0);
  }
  80% {
    opacity: 1;
    transform: translateX(-50%) translateY(0);
  }
  100% {
    opacity: 0;
    transform: translateX(-50%) translateY(-10px);
  }
}

/* 图层控制面板样式 */
.layer-panel {
  position: absolute;
  top: 20px;
  right: 20px;
  width: 280px;
  background: rgba(255, 255, 255, 0.95);
  border-radius: 12px;
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.1);
  z-index: 20;
  backdrop-filter: blur(10px);
}

.panel-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 16px 20px;
  border-bottom: 1px solid rgba(0, 0, 0, 0.1);
}

.panel-header h3 {
  margin: 0;
  font-size: 16px;
  font-weight: 600;
  color: #333;
}

.toggle-btn {
  background: none;
  border: none;
  cursor: pointer;
  color: #666;
  font-size: 14px;
  padding: 4px;
  border-radius: 4px;
  transition: all 0.2s;
}

.toggle-btn:hover {
  background: rgba(0, 0, 0, 0.05);
  color: #333;
}

.layer-list {
  max-height: 300px;
  overflow-y: auto;
  padding: 8px 0;
}

.layer-item {
  padding: 8px 20px;
  border-bottom: 1px solid rgba(0, 0, 0, 0.05);
  transition: all 0.2s;
}

.layer-item:hover {
  background: rgba(0, 0, 0, 0.02);
}

.layer-item.selected {
  background: rgba(74, 144, 226, 0.15);
  border-left: 4px solid #4a90e2;
  box-shadow: 0 2px 8px rgba(74, 144, 226, 0.2);
}

.layer-controls {
  display: flex;
  align-items: center;
  gap: 12px;
}

.visibility-toggle {
  width: 16px;
  height: 16px;
  cursor: pointer;
}

.layer-name {
  flex: 1;
  font-size: 14px;
  color: #333;
  cursor: pointer;
  user-select: none;
}

.layer-name:hover {
  color: #4a90e2;
}

.layer-item.selected .layer-name {
  color: #4a90e2;
  font-weight: 600;
}

.layer-actions {
  display: flex;
  gap: 4px;
}

.action-btn {
  width: 24px;
  height: 24px;
  border: none;
  background: rgba(0, 0, 0, 0.05);
  border-radius: 4px;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 12px;
  color: #666;
  transition: all 0.2s;
}

.action-btn:hover {
  background: rgba(74, 144, 226, 0.1);
  color: #4a90e2;
}

/* 滚动条样式 */
.layer-list::-webkit-scrollbar {
  width: 6px;
}

.layer-list::-webkit-scrollbar-track {
  background: rgba(0, 0, 0, 0.05);
  border-radius: 3px;
}

.layer-list::-webkit-scrollbar-thumb {
  background: rgba(0, 0, 0, 0.2);
  border-radius: 3px;
}

.layer-list::-webkit-scrollbar-thumb:hover {
  background: rgba(0, 0, 0, 0.3);
}
</style>
